from datetime import date
from typing import Literal, Any
from utils.enums import SCE
from utils.exceptions import BusinessException
from decimal import Decimal


type CarType = Literal['ae4cf7daafbb43518fbc0659cf203ab1', '26953534c7184ffc9d98ef159a0d7eec', 'b703f6bd11b24e0c89f61402b593fe28', '4abcafd674da457c86301f9df866950c']
car_type_dict: dict[str, CarType] = {
    '角钢': 'ae4cf7daafbb43518fbc0659cf203ab1',
    '带钢': '26953534c7184ffc9d98ef159a0d7eec',
    '钢坯': '4abcafd674da457c86301f9df866950c',
    '废品销售': 'b703f6bd11b24e0c89f61402b593fe28',
}

type POUND_LIST_STATE = Literal['1', '', '0']
checklist_state: dict[str, POUND_LIST_STATE] = {
    '已关闭': '1',
    '全部': '',
    '未关闭': '0'
}


# 一般类型检查
class ParamCheck:

    @staticmethod
    def checklist_state(data: Any) -> POUND_LIST_STATE:
        if data not in checklist_state.keys():
            raise BusinessException(SCE.ParamError)
        else:
            return checklist_state[data]

    @staticmethod
    def car_type(data: Any) -> CarType:
        if data not in car_type_dict.keys():
            raise BusinessException(SCE.ParamError)
        else:
            return car_type_dict[data]

    @staticmethod
    def decimal(data: Any, force: bool = True) -> Decimal | None:
        if force is False and data is None:
            return data
        try:
            if data == '':
                data = '0'
            data = Decimal(str(data)).quantize(Decimal('0.000'))
            if data > Decimal('99999999.999'):
                raise BusinessException(SCE.ParamError)
            return data
        except Exception:
            raise BusinessException(SCE.ParamError)

    # 检查日期范围
    @staticmethod
    def date_range(data: Any, date_type: Literal['str', 'date'] = 'date', force: bool = True) -> tuple[date, date] | tuple[str, str] | None:
        if force is False and data is None:
            return None
        try:
            if len(data) != 2:
                raise BusinessException(SCE.ParamError)
            date1 = date.fromisoformat(data[0])
            date2 = date.fromisoformat(data[1])
            if date_type == 'date':
                return date1, date2
            else:
                return date1.strftime('%Y-%m-%d'), date2.strftime('%Y-%m-%d')
        except (TypeError, ValueError, IndexError):
            raise BusinessException(SCE.ParamError)

    # 检查日期是否符合标准
    @staticmethod
    def date(data: Any, force: bool = True) -> date | None:
        if force is False and data is None:
            return data
        try:
            return date.fromisoformat(data)
        except (TypeError, ValueError, AttributeError):
            raise BusinessException(SCE.ParamError)

    # 检查是否为整数,如果提供范围则也检查范围，如果是字符串则将尝试转为整数
    @staticmethod
    def int(data: Any, length: tuple[int, int] = None, force: bool = True) -> int | None:
        if force is False and data is None:
            return data
        if type(data) is not int:
            if type(data) is str or bool:
                try:
                    data = int(data)
                except (ValueError, TypeError, AttributeError):
                    raise BusinessException(SCE.ParamError)
                return data
            else:
                return data
        if length is not None:
            if data < length[0] or data > length[1]:
                raise BusinessException(SCE.ParamError)
        return data

    # 检查是否为整数数组[10, 20]，且数组中后数大于前数
    @staticmethod
    def int_range(data: Any, force: bool = True) -> tuple[int, int] | None:
        if force is False and data is None:
            return data
        if type(data) is not list:
            raise BusinessException(SCE.ParamError)
        if len(data) != 2:
            raise BusinessException(SCE.ParamError)
        if type(data[0]) is not int or type(data[1]) is not int:
            raise BusinessException(SCE.ParamError)
        return data

    # 检查是否为字符串，如果是没有传入该参数或者该参数为空字符串，则一律返回None
    @staticmethod
    def str(data: Any, length: tuple[int, int] = None, force: bool = True) -> str | None:
        if force is False and (data is None or data == '') :
            return None
        if type(data) is not str:
            raise BusinessException(SCE.ParamError)
        if length is not None:
            if len(data) < length[0] or len(data) > length[1]:
                raise BusinessException(SCE.ParamError)
        return data

    @staticmethod
    def bool(data: Any, force: bool = True) -> bool | None:
        if force is False and data is None:
            return data

        if type(data) is not bool:
            raise BusinessException(SCE.ParamError)
        return data
